#include "Keyboard.hpp"

OIS::Keyboard* OgreMax::Keyboard::GetKeyboard()
{
    return this->keyboard;
}

bool OgreMax::Keyboard::IsNull() const
{
    return this->keyboard == 0;
}

bool OgreMax::Keyboard::PressedKey(OIS::KeyCode keyCode) const
{
    return
        this->keyboard != 0 &&
        !this->previousKeys[(int)keyCode] &&
        this->keys[(int)keyCode];
}

bool OgreMax::Keyboard::PressingKey(OIS::KeyCode keyCode) const
{
    return
        this->keyboard != 0 &&
        this->keys[(int)keyCode];
}

bool OgreMax::Keyboard::ReleasedKey(OIS::KeyCode keyCode) const
{
    return
        this->keyboard != 0 &&
        this->previousKeys[(int)keyCode] &&
        !this->keys[(int)keyCode];
}

bool OgreMax::Keyboard::PressedAnyKey() const
{
    for(int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++){
        OIS::KeyCode keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
        if (PressedKey(keyCode))
            return true;
    }

    return false;
}

bool OgreMax::Keyboard::PressingAnyKey() const
{
    const long* longKeys = (long*)this->keys;
    const int longKeyCount = KEY_COUNT / sizeof(long);

    for (int i = 0; i < longKeyCount; i++)
    {
        if (longKeys[i] != 0)
            return true;
    }

    return false;

    //return
    //    this->keyboard != 0 &&
    //    CheckPressingAnyKey(this->keys);
}



bool OgreMax::Keyboard::ReleasedAnyKey() const
{
    for(int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++){
        OIS::KeyCode keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
        if (ReleasedKey(keyCode))
            return true;
    }

    return false;
}

OIS::KeyCode OgreMax::Keyboard::GetPressedKey(int* modifierFlags /*= 0*/) const
{
    OIS::KeyCode returnKeyCode = OIS::KC_UNASSIGNED;
    OIS::KeyCode keyCode;

    if (modifierFlags != 0)
    {
        *modifierFlags = 0;

        if (PressingKey(OIS::KC_LMENU) || PressingKey(OIS::KC_RMENU))
            *modifierFlags |= ALT_MODIFIER;
        if (PressingKey(OIS::KC_LCONTROL) || PressingKey(OIS::KC_RCONTROL))
            *modifierFlags |= CTRL_MODIFIER;
        if (PressingKey(OIS::KC_LSHIFT) || PressingKey(OIS::KC_RSHIFT))
            *modifierFlags |= SHIFT_MODIFIER;

        for (int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++)
        {
            keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
            if (PressedKey(keyCode) && !IsModifierKey(keyCode))
            {
                returnKeyCode = keyCode;
                break;
            }
        }

        return returnKeyCode;
    }
    else
    {
        for (int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++)
        {
            keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
            if (PressedKey(keyCode))
            {
                returnKeyCode = keyCode;
                break;
            }
        }
    }

    return returnKeyCode;
}

OIS::KeyCode OgreMax::Keyboard::GetPressingKey(int* modifierFlags /*= 0*/) const
{
    OIS::KeyCode returnKeyCode = OIS::KC_UNASSIGNED;
    OIS::KeyCode keyCode;

    if (modifierFlags != 0)
    {
        *modifierFlags = 0;

        if (PressingKey(OIS::KC_LMENU) || PressingKey(OIS::KC_RMENU))
            *modifierFlags |= ALT_MODIFIER;
        if (PressingKey(OIS::KC_LCONTROL) || PressingKey(OIS::KC_RCONTROL))
            *modifierFlags |= CTRL_MODIFIER;
        if (PressingKey(OIS::KC_LSHIFT) || PressingKey(OIS::KC_RSHIFT))
            *modifierFlags |= SHIFT_MODIFIER;

        for (int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++)
        {
            keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
            if (PressingKey(keyCode) && !IsModifierKey(keyCode))
            {
                returnKeyCode = keyCode;
                break;
            }
        }

        return returnKeyCode;
    }
    else
    {
        for (int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++)
        {
            keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
            if (PressingKey(keyCode))
            {
                returnKeyCode = keyCode;
                break;
            }
        }
    }

    return returnKeyCode;
}

OIS::KeyCode OgreMax::Keyboard::GetReleasedKey() const
{
    OIS::KeyCode returnKeyCode = OIS::KC_UNASSIGNED;

    OIS::KeyCode keyCode;
    for (int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++)
    {
        keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
        if (ReleasedKey(keyCode))
        {
            returnKeyCode = keyCode;
            break;
        }
    }

    return returnKeyCode;
}

void OgreMax::Keyboard::GetPressedKeys(InputSourceVector& inputSources) const
{
    InputSource inputSource;
    inputSource.deviceType = InputSource::KEYBOARD_KEY;
    for (int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++)
    {
        inputSource.keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
        if (PressedKey(inputSource.keyCode))
            inputSources.push_back(inputSource);
    }
}

void OgreMax::Keyboard::GetPressingKeys(InputSourceVector& inputSources) const
{
    InputSource inputSource;
    inputSource.deviceType = InputSource::KEYBOARD_KEY;
    for (int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++)
    {
        inputSource.keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
        if (PressingKey(inputSource.keyCode))
            inputSources.push_back(inputSource);
    }
}

void OgreMax::Keyboard::GetReleasedKeys(InputSourceVector& inputSources) const
{
    InputSource inputSource;
    inputSource.deviceType = InputSource::KEYBOARD_KEY;
    for (int keyIndex = 0; keyIndex < KEY_COUNT; keyIndex++)
    {
        inputSource.keyCode = OIS::KeyCode(OIS::KC_UNASSIGNED + keyIndex);
        if (ReleasedKey(inputSource.keyCode))
            inputSources.push_back(inputSource);
    }
}

bool OgreMax::Keyboard::IsAltKey(OIS::KeyCode keyCode)
{
    return keyCode == OIS::KC_LMENU || keyCode == OIS::KC_RMENU;
}

bool OgreMax::Keyboard::IsCtrlKey(OIS::KeyCode keyCode)
{
    return keyCode == OIS::KC_LCONTROL || keyCode == OIS::KC_RCONTROL;
}

bool OgreMax::Keyboard::IsShiftKey(OIS::KeyCode keyCode)
{
    return keyCode == OIS::KC_LSHIFT || keyCode == OIS::KC_RSHIFT;
}

bool OgreMax::Keyboard::IsModifierKey(OIS::KeyCode keyCode)
{
    return IsAltKey(keyCode) || IsCtrlKey(keyCode) || IsShiftKey(keyCode);
}

bool OgreMax::Keyboard::IsFunctionKey(OIS::KeyCode keyCode)
{
    switch (keyCode)
    {
    case OIS::KC_F1:
    case OIS::KC_F2:
    case OIS::KC_F3:
    case OIS::KC_F4:
    case OIS::KC_F5:
    case OIS::KC_F6:
    case OIS::KC_F7:
    case OIS::KC_F8:
    case OIS::KC_F9:
    case OIS::KC_F10:
    case OIS::KC_F11:
    case OIS::KC_F12:
    case OIS::KC_F13:
    case OIS::KC_F14:
    case OIS::KC_F15: return true;
    default: return false;
    }
}

bool OgreMax::Keyboard::IsNumberKey(OIS::KeyCode keyCode)
{
    return ToNumber(keyCode) != -1;
}

int OgreMax::Keyboard::ToNumber(OIS::KeyCode keyCode)
{
    switch (keyCode)
    {
    case OIS::KC_0: return 0;
    case OIS::KC_1: return 1;
    case OIS::KC_2: return 2;
    case OIS::KC_3: return 3;
    case OIS::KC_4: return 4;
    case OIS::KC_5: return 5;
    case OIS::KC_6: return 6;
    case OIS::KC_7: return 7;
    case OIS::KC_8: return 8;
    case OIS::KC_9: return 9;
    case OIS::KC_NUMPAD0: return 0;
    case OIS::KC_NUMPAD1: return 1;
    case OIS::KC_NUMPAD2: return 2;
    case OIS::KC_NUMPAD3: return 3;
    case OIS::KC_NUMPAD4: return 4;
    case OIS::KC_NUMPAD5: return 5;
    case OIS::KC_NUMPAD6: return 6;
    case OIS::KC_NUMPAD7: return 7;
    case OIS::KC_NUMPAD8: return 8;
    case OIS::KC_NUMPAD9: return 9;
    default: return -1;
    }
}

OgreMax::Keyboard::Keyboard()
{
    this->keyboard = 0;
    this->updatedOnce = false;

    memset(this->keyBuffers, 0, KEY_BUFFER_BYTE_SIZE);

    SetKeyBuffers(0);
}

void OgreMax::Keyboard::Set(OIS::Keyboard* keyboard)
{
    this->keyboard = keyboard;
    this->updatedOnce = false;
}

void OgreMax::Keyboard::Update()
{
    if (this->keyboard != 0)
    {
        //Switch buffers
        SetKeyBuffers(this->keyBufferIndex ^ 1);

        //Get the current keys
        this->keyboard->capture();
        this->keyboard->copyKeyStates(this->keys);

        //Copy the current keys to the previous if this is the first update
        if (!this->updatedOnce)
        {
            memcpy(this->previousKeys, this->keys, KEY_COUNT);
            this->updatedOnce = true;
        }
    }
}

void OgreMax::Keyboard::SetKeyBuffers(int currentKeyBufferIndex)
{
    this->keyBufferIndex = currentKeyBufferIndex;
    this->keys = this->keyBuffers[this->keyBufferIndex];
    this->previousKeys = this->keyBuffers[this->keyBufferIndex ^ 1];
}

//bool OgreMax::Keyboard::CheckPressingAnyKey(const char* keys)
//{
//    const long* longKeys = (long*)keys;
//    const int longKeyCount = KEY_COUNT / sizeof(long);
//
//    for (int i = 0; i < longKeyCount; i++)
//    {
//        if (longKeys[i] != 0)
//            return true;
//    }
//
//    return false;
//}
